#pragma once

#include "imageclass_decl.h"

namespace img {

typedef unsigned char byte_color::*color_component;
typedef img::projection_raster<byte_image, unsigned char>		color_plane;
typedef img::const_projection_raster<byte_image, unsigned char>	const_color_plane;

//T is class of image containter hereafter

template <class T>
class color_plane_containter
{
public:
	color_plane_containter(const T & dd, color_component cc) : d(dd), c(cc) { }
	size_t size() const
		{ return d.size(); }
	const_color_plane operator [] (int n) const
		{ return const_color_plane(d[n], c); }
private:
	const T & d;
	color_component c;
};

template <class T, class O>
void time_median(T const & d, size_t first, size_t last, O & out)
{
	const size_t s = last - first;
	assert (s > 0);
	if (s == 1) {
		out = d[first];
		return;
	}
	const size_t mid = (s-1)/2;
	const bool odd = s % 2 == 1;
	std::vector<typename O::elem_type> a(s);

	typename O::iterator i;
	for (i = out.begin(); i != out.end(); ++i) { 
		for (size_t j = 0; j < s; ++j)
			a[j] = d[j + first][i];
		std::nth_element(a.begin(), a.begin()+mid, a.end());
		if (odd)
			*i = a[mid];
		else {
			std::nth_element(a.begin()+mid+1, a.begin()+mid+1, a.end());
			*i = (a[mid] + a[mid+1]) / 2;
		}
	}
}

template <class T, class O>
inline void time_median(T const & d, O & out)
{
	time_median(d, 0, d.size(), out);
}

template <class T>
void color_time_median(T const & d, size_t first, size_t last, byte_image & out)
{
	color_plane b(out, &byte_color::b);
	color_plane g(out, &byte_color::g);
	color_plane r(out, &byte_color::r);

	time_median(color_plane_containter<T>(d, &byte_color::b), first, last, b);
	time_median(color_plane_containter<T>(d, &byte_color::g), first, last, g);
	time_median(color_plane_containter<T>(d, &byte_color::r), first, last, r);
}

template <class T>
inline void color_time_median(T const & d, byte_image & out)
{
	color_time_median(d, 0, d.size(), out);
}

template <class T>
void bit_time_median(T const & d, size_t first, size_t last, bitmap & out)
{
	const size_t s = last - first;
	assert (s > 0);
	if (s == 1) {
		out = d[first];
		return;
	}
	const size_t mid = (s-1)/2;

	bitmap::iterator i;
	for (i = out.begin(); i != out.end(); ++i) { 
		int a = 0;
		for (int j = first; j < last; ++j)
			if (d[j][i])
				++a;
		*i = a > mid;
	}
}

template <class T>
inline void bit_time_median(T const & d, bitmap & out)
{
	bit_time_median(d, 0, d.size(), out);
}

} //namespace img